其他
CVE-2021-24086漏洞分析
本文为看雪论坛精华文章
看雪论坛作者ID:badboyl
一
漏洞信息
二
漏洞复现
python3 cve-2021-24086.py --target fe80::69eb:90bf:3f91:deae
三
漏洞分析
0: kd> r
rax=0000000000000000 rbx=0000000000000003 rcx=0000000000000003
rdx=000000000000008a rsi=fffff800042531c0 rdi=0000000000000000
rip=fffff800040f9720 rsp=fffff800054d5218 rbp=0000000000000000
r8=0000000000000065 r9=0000000000000000 r10=0000000000000000
r11=fffff800054d4ea0 r12=000000000000000a r13=0000000000000001
r14=0000000040000082 r15=0000000000000000
iopl=0 nv up ei ng nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000282
nt!RtlpBreakWithStatusInstruction:
fffff800`040f9720 cc int 3
0: kd> kb
# RetAddr : Args to Child : Call Site
00 fffff800`041adc22 : 00000000`00000000 fffff800`042531c0 00000000`00000065 fffff800`040ca378 : nt!RtlpBreakWithStatusInstruction
01 fffff800`041aea12 : 00000000`00000003 00000000`00000000 fffff800`041025d0 00000000`000000d1 : nt!KiBugCheckDebugBreak+0x12
02 fffff800`040f2fa4 : 00000000`00000000 fffff800`04259888 fffff800`04259a02 fffff800`0408e00a : nt!KeBugCheck2+0x722
03 fffff800`041012e9 : 00000000`0000000a 00000000`00000000 00000000`00000002 00000000`00000001 : nt!KeBugCheckEx+0x104
04 fffff800`040ff0ce : 00000000`00000001 00000000`00000000 fffffa80`32dc6500 00000000`00010010 : nt!KiBugCheckDispatch+0x69
05 fffff880`018884bd : fffff880`01920bff 00000000`00010010 fffffa80`00000060 fffffa80`339b15e0 : nt!KiPageFault+0x44e
06 fffff880`01920bff : 00000000`00010010 fffffa80`00000060 fffffa80`339b15e0 00000000`00000000 : tcpip!memmove+0xbd
07 fffff880`01938d18 : fffffa80`31fb1000 00000000`00000000 fffffa80`32dc6702 00000000`0000fffa : tcpip!Ipv6pReassembleDatagram+0x17f
08 fffff880`01938e03 : fffffa80`00000008 fffff880`0196b738 fffffa80`32dfe8d0 fffffa80`31e96900 : tcpip!Ipv6pReceiveFragment+0xb58
09 fffff880`01858964 : 0000057f`cd9e03a8 fffffa80`334a81b0 fffffa80`334a81b0 fffff880`01003e8b : tcpip!Ipv6pReceiveFragmentList+0x43
0a fffff880`0185642f : 00000000`00000000 00000000`0199c801 00000000`00000000 fffff880`01966870 : tcpip!IppReceiveHeaderBatch+0x485
0b fffff880`01855a4c : fffffa80`32e0b960 00000000`00000000 fffff880`0199c801 fffffa80`00000001 : tcpip!IpFlcReceivePackets+0x64f
0c fffff880`0185443a : fffffa80`32e13ba0 fffff800`054d6250 fffffa80`32e13ba0 00000003`e9110001 : tcpip!FlpReceiveNonPreValidatedNetBufferListChain+0xcec
0d fffff800`040a8dd9 : fffffa80`32dc65e0 00000000`00000000 fffffa80`31e9c830 00000000`00000000 : tcpip!FlReceiveNetBufferListChainCalloutRoutine+0xda
0e fffff880`01854b32 : fffff880`01854360 fffff800`054d6370 fffffa80`00000000 ffff0092`174ff900 : nt!KeExpandKernelStackAndCalloutEx+0x2c9
0f fffff880`017a70eb : fffffa80`32e148d0 00000000`00000000 fffffa80`3aef21a0 00000000`00000000 : tcpip!FlReceiveNetBufferListChain+0xb2
10 fffff880`01770ad6 : fffff800`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ndis!ndisMIndicateNetBufferListsToOpen+0xdb
11 fffff880`016fd599 : fffffa80`3aef21a0 00000000`00000002 00000000`00000001 00000000`00000001 : ndis!ndisMDispatchReceiveNetBufferLists+0x1d6
12 fffff880`016f37a4 : 00000000`00010303 00000000`00000000 00000000`00000001 fffff880`016f2900 : ndis!ndisMDispatchReceiveNetBufferListsWithLock+0x89
13 fffff880`016f3719 : 00000000`00000000 fffff880`05885759 fffffa80`32e02010 00000000`00000000 : ndis!ndisMTopReceiveNetBufferLists+0x24
14 fffff880`016f36b0 : 00000000`00000000 00000000`00000009 00000000`00000000 00000000`00000001 : ndis!ndisFilterIndicateReceiveNetBufferLists+0x29
15 fffff880`058858e1 : fffffa80`32e02010 00000000`00000001 00000000`00000001 fffffa80`32dc65e0 : ndis!NdisFIndicateReceiveNetBufferLists+0x50
16 fffff880`0170bc24 : fffffa80`3aef21a0 fffffa80`32dc65e0 00000000`00000001 fffffa80`32dc65e0 : npcap+0x58e1
17 fffff880`0627c778 : 00000000`00000000 00000000`00000001 00000000`00000000 00000000`00000000 : ndis! ?? ::FNODOBFM::`string'+0xc72f
18 fffff880`0627c3d1 : fffffa80`325ad001 00000000`00000000 00000000`00000000 fffffa80`32611000 : E1G6032E+0x778
19 fffff880`016ea9b6 : fffffa80`32dd1670 00000000`00000000 fffffa80`3aef21a0 00000000`00000018 : E1G6032E+0x3d1
1a fffff800`0409fcbc : fffffa80`32dd1698 fffff800`00000000 00000000`00000000 fffff800`04243180 : ndis!ndisInterruptDpc+0x1b6
1b fffff800`040f642a : fffff800`04243180 fffff800`042531c0 00000000`00000000 fffff880`016ea800 : nt!KiRetireDpcList+0x1bc
1c 00000000`00000000 : fffff800`054d7000 fffff800`054d1000 fffff800`054d6c00 00000000`00000000 : nt!KiIdleLoop+0x5a
0: kd> .trap 0xfffff880`01938d18
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
Unable to get program counter
rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=c328c48348000001 rsp=5718738949106b89 rbp=3301b04128ec8348
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 vip vif ov up ei pl zr na po nc
9090:0001 ?? ???
rax=402cfaff00000060 rbx=0000000000000000 rcx=0000000000000020
rdx=fffffa8032c2f198 rsi=0000000000000000 rdi=0000000000000000
rip=fffff880018884bd rsp=fffff800054d5c68 rbp=fffffa8032c2f110
r8=0000000000000028 r9=0000000000000001 r10=00000000000080fe
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na pe nc
tcpip!memmove+0xbd:
fffff880`018884bd 488941e0 mov qword ptr [rcx-20h],rax ds:00000000`00000000=????????????????
Resetting default scope
BytesNeededa = (char *)NdisGetDataBuffer((PNET_BUFFER)v14, BytesNeeded, 0i64, 1u, 0);
v16 = IppCopyPacket(v7, a1);
if ( !v16 )
goto LABEL_8;
*(_WORD *)(a2 + 140) = __ROR2__(v29, 8);
memmove(BytesNeededa, (const void *)(a2 + 136), 0x28ui64);
memmove(BytesNeededa + 40, *(const void **)(a2 + 96), *(unsigned __int16 *)(a2 + 104));
BytesNeededa[*(unsigned __int16 *)(a2 + 184)] = *(_BYTE *)(a2 + 188);
NDIS_EXPORTED_ROUTINE PVOID NdisGetDataBuffer(
[in] NET_BUFFER *NetBuffer,
[in] ULONG BytesNeeded,
[in, optional] PVOID Storage,
[in] ULONG AlignMultiple,
[in] ULONG AlignOffset
);
从官方的MSDN可以的知,该值可以是指针也可能是NULL,而在下面没有经过判断就往内存写入,如果当内存的地址为0时,就触发了BSOD。
通过逆向分析发现NdisGetDataBuffer有几处if判断可能会将其写入0。
NDIS_STATUS __stdcall NdisRetreatNetBufferDataStart(PNET_BUFFER NetBuffer, ULONG DataOffsetDelta, ULONG DataBackFill, NET_BUFFER_ALLOCATE_MDL_HANDLER AllocateMdlHandler)
{
unsigned int v5; // ecx
_MDL *v7; // rax
unsigned int v8; // ecx
unsigned int v9; // edx
_MDL *v11; // rax
ULONG v12; // ecx
ULONG v13; // [rsp+38h] [rbp+10h] BYREF
v5 = NetBuffer->DataOffset; // v5=0
if ( v5 >= DataOffsetDelta ) // v5=0;dataoffsetdelta=28
{
v7 = NetBuffer->MdlChain;
NetBuffer->DataLength += DataOffsetDelta;
v8 = v5 - DataOffsetDelta;
for ( NetBuffer->DataOffset = v8; v7; v8 -= v9 )
{
v9 = v7->ByteCount;
if ( v8 < v9 )
break;
v7 = v7->Next;
}
NetBuffer->Link.Region = (unsigned __int64)v7;
goto LABEL_5;
}
v13 = DataBackFill + DataOffsetDelta - v5;
if ( !AllocateMdlHandler ) // AllocateMdlHandler=true
AllocateMdlHandler = ndisAllocateMdl;
v11 = (_MDL *)((__int64 (__fastcall *)(ULONG *))AllocateMdlHandler)(&v13);
if ( v11 ) // v11=true
{
v11->Next = NetBuffer->MdlChain;
v12 = v13;
NetBuffer->MdlChain = v11;
NetBuffer->Link.Region = (unsigned __int64)v11;
NetBuffer->DataOffset += v12 - DataOffsetDelta;
v8 = NetBuffer->DataOffset;
NetBuffer->DataLength += DataOffsetDelta; // NetBuffer->DataLength=28
LABEL_5:
NetBuffer->CurrentMdlOffset = v8;
return 0;
}
return -1073741670;
}
if ( v15 < (unsigned __int16)BytesNeeded )
{
if ( NdisRetreatNetBufferDataStart(netbuffer, (unsigned __int16)BytesNeeded, 0, NetioAllocateMdl_0) < 0 )
{
LABEL_8:
IppRemoveFromReassemblySet((PKSPIN_LOCK)(v7 + 20168));
NetioDereferenceNetBufferList_0(v13, 0i64);
goto LABEL_24;
}
}
else
{
netbuffer->DataOffset -= (unsigned __int16)BytesNeeded;
netbuffer->DataLength += (unsigned __int16)BytesNeeded;// ((a2+104)+40) 2个字节
netbuffer->CurrentMdlOffset = v15 - (unsigned __int16)BytesNeeded;
}
BytesNeededa = (char *)NdisGetDataBuffer(netbuffer, BytesNeeded, 0i64, 1u, 0);
0: kd> p
tcpip!Ipv6pReassembleDatagram+0xa:
fffff880`01923a8a 53 push rbx
0: kd> p
tcpip!Ipv6pReassembleDatagram+0xb:
fffff880`01923a8b 55 push rbp
0: kd> p
tcpip!Ipv6pReassembleDatagram+0xc:
fffff880`01923a8c 56 push rsi
0: kd> p
tcpip!Ipv6pReassembleDatagram+0xd:
fffff880`01923a8d 57 push rdi
0: kd> p
tcpip!Ipv6pReassembleDatagram+0xe:
fffff880`01923a8e 4154 push r12
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x10:
fffff880`01923a90 4155 push r13
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x12:
fffff880`01923a92 4156 push r14
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x14:
fffff880`01923a94 4157 push r15
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x16:
fffff880`01923a96 4883ec58 sub rsp,58h
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x1a:
fffff880`01923a9a 440fb74a68 movzx r9d,word ptr [rdx+68h]
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x1f:
fffff880`01923a9f 8b426c mov eax,dword ptr [rdx+6Ch]
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x22:
fffff880`01923aa2 418af8 mov dil,r8b
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x25:
fffff880`01923aa5 4103c1 add eax,r9d
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x28:
fffff880`01923aa8 488bea mov rbp,rdx
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x2b:
fffff880`01923aab 898424b8000000 mov dword ptr [rsp+0B8h],eax
0: kd>
tcpip!Ipv6pReassembleDatagram+0x32:
fffff880`01923ab2 83c028 add eax,28h
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x35:
fffff880`01923ab5 89442430 mov dword ptr [rsp+30h],eax
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x39:
fffff880`01923ab9 418d4128 lea eax,[r9+28h]
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x3d:
fffff880`01923abd 898424a8000000 mov dword ptr [rsp+0A8h],eax
0: kd> p
tcpip!Ipv6pReassembleDatagram+0x44:
fffff880`01923ac4 488b81d0000000 mov rax,qword ptr [rcx+0D0h]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x4b:
fffff880`01923acb 33c9 xor ecx,ecx
0: kd>
tcpip!Ipv6pReassembleDatagram+0x4d:
fffff880`01923acd 488b5808 mov rbx,qword ptr [rax+8]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x51:
fffff880`01923ad1 488b03 mov rax,qword ptr [rbx]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x54:
fffff880`01923ad4 4c8bb088020000 mov r14,qword ptr [rax+288h]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x5b:
fffff880`01923adb ff152ff80100 call qword ptr [tcpip!_imp_KeGetCurrentProcessorNumberEx (fffff880`01943310)]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x61:
fffff880`01923ae1 488d0d48edefff lea rcx,[tcpip!IppReassemblyNetBufferListsComplete (fffff880`01822830)]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x68:
fffff880`01923ae8 448be8 mov r13d,eax
0: kd>
tcpip!Ipv6pReassembleDatagram+0x6b:
fffff880`01923aeb 488b8330030000 mov rax,qword ptr [rbx+330h]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x72:
fffff880`01923af2 4533c9 xor r9d,r9d
0: kd>
tcpip!Ipv6pReassembleDatagram+0x75:
fffff880`01923af5 4e8b3ce8 mov r15,qword ptr [rax+r13*8]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x79:
fffff880`01923af9 49c1e508 shl r13,8
0: kd>
tcpip!Ipv6pReassembleDatagram+0x7d:
fffff880`01923afd 4533c0 xor r8d,r8d
0: kd>
tcpip!Ipv6pReassembleDatagram+0x80:
fffff880`01923b00 4d03ae284e0000 add r13,qword ptr [r14+4E28h]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x87:
fffff880`01923b07 488bd5 mov rdx,rbp
0: kd>
tcpip!Ipv6pReassembleDatagram+0x8a:
fffff880`01923b0a c644242800 mov byte ptr [rsp+28h],0
0: kd>
tcpip!Ipv6pReassembleDatagram+0x8f:
fffff880`01923b0f 8364242000 and dword ptr [rsp+20h],0
0: kd>
tcpip!Ipv6pReassembleDatagram+0x94:
fffff880`01923b14 e8f3d7f2ff call tcpip!NetioAllocateAndReferenceNetBufferAndNetBufferList (fffff880`0185130c)
0: kd>
tcpip!Ipv6pReassembleDatagram+0x99:
fffff880`01923b19 4c8be0 mov r12,rax
0: kd>
tcpip!Ipv6pReassembleDatagram+0x9c:
fffff880`01923b1c 4885c0 test rax,rax
0: kd>
tcpip!Ipv6pReassembleDatagram+0x9f:
fffff880`01923b1f 7517 jne tcpip!Ipv6pReassembleDatagram+0xb8 (fffff880`01923b38)
0: kd>
tcpip!Ipv6pReassembleDatagram+0xb8:
fffff880`01923b38 488b7008 mov rsi,qword ptr [rax+8]
0: kd>
tcpip!Ipv6pReassembleDatagram+0xbc:
fffff880`01923b3c 8b9c24a8000000 mov ebx,dword ptr [rsp+0A8h]
0: kd>
tcpip!Ipv6pReassembleDatagram+0xc3:
fffff880`01923b43 8b4610 mov eax,dword ptr [rsi+10h]
0: kd>
tcpip!Ipv6pReassembleDatagram+0xc6:
fffff880`01923b46 0fb7d3 movzx edx,bx
0: kd>
tcpip!Ipv6pReassembleDatagram+0xc9:
fffff880`01923b49 3bc2 cmp eax,edx
0: kd>
tcpip!Ipv6pReassembleDatagram+0xcb:
fffff880`01923b4b 724e jb tcpip!Ipv6pReassembleDatagram+0x11b (fffff880`01923b9b)
0: kd>
tcpip!Ipv6pReassembleDatagram+0x11b:
fffff880`01923b9b 4c8d0dbeaff2ff lea r9,[tcpip!NetioAllocateMdl (fffff880`0184eb60)]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x122:
fffff880`01923ba2 4533c0 xor r8d,r8d
0: kd>
tcpip!Ipv6pReassembleDatagram+0x125:
fffff880`01923ba5 488bce mov rcx,rsi
0: kd>
tcpip!Ipv6pReassembleDatagram+0x128:
fffff880`01923ba8 ff15c2020200 call qword ptr [tcpip!_imp_NdisRetreatNetBufferDataStart (fffff880`01943e70)]
0: kd>
tcpip!Ipv6pReassembleDatagram+0x12e:
fffff880`01923bae 85c0 test eax,eax
0: kd>
tcpip!Ipv6pReassembleDatagram+0x130:
fffff880`01923bb0 79a6 jns tcpip!Ipv6pReassembleDatagram+0xd8 (fffff880`01923b58)
0: kd>
tcpip!Ipv6pReassembleDatagram+0xd8:
fffff880`01923b58 8364242000 and dword ptr [rsp+20h],0
0: kd> r
rax=0000000000000000 rbx=0000000000000028 rcx=0000000000000038
rdx=fffffa8033468541 rsi=fffffa8032587400 rdi=fffffa80322db002
rip=fffff88001923b58 rsp=fffff80000b9dcd0 rbp=fffffa8033f5c6e0
r8=fffffa8033468540 r9=fffff8800184eb60 r10=fffffa8033468020
r11=fffffa8033468540 r12=fffffa80325872d0 r13=fffffa80321ba900
r14=fffff88001969870 r15=fffffa80334308d0
iopl=0 nv up ei pl zr na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000246
包分片其实在上学的时候就应该说过了,如果数据包的大小超过最大传输单元(MTU)的时候就会重组,从而还原一条完整的流。
Ipv6pReassembleDatagram是主要的问题函数,用来处理嵌套分片包时NET_BUFFER结构中读取扩展头的长度+ sizeof(IPv6_header)字节。IPv6头的大小从上面的动态调试得知为0x28。
上面提到过MSDN指出NdisGetDataBuffer是会返回NULL的情况,可以使NET_BUFFER为NULL,NdisGetDataBuffer则返回NULL,而当在上下文被引用时则会触发BSOD空指针引用。
POC中可以看到通过特制的扩展头identification来使程序触发异常,关于包重组的细节在蝶澈的文章(https://bbs.pediy.com/thread-266955.htm)中阐述的我认为已经算是全网最详细的了,这里不再复述。
四
总结
看雪ID:badboyl
https://bbs.pediy.com/user-home-748627.htm
# 往期推荐
2.Frida inlineHook原理分析及简单设计一款AArch64 inlineHook工具
球分享
球点赞
球在看
点击“阅读原文”,了解更多!